Conversation
…correction) Completes the input pipeline for TemporalCoordinationDetection. phaseLockingValue (PR #298): PLV expects phases in radians but didn't prescribe how events become phases. This ship fills the gap. 17th graduation under Otto-105 cadence. Addresses Amara 17th-ferry Part 2 correction #5: 'Without phase construction, PLV is just a word.' Surface (2 pure functions): - PhaseExtraction.epochPhase : double -> double[] -> double[] Periodic-epoch phase. φ(t) = 2π · (t mod period) / period. Suited to consensus-protocol events with fixed cadence (slot duration, heartbeat, epoch boundary). - PhaseExtraction.interEventPhase : double[] -> double[] -> double[] Circular phase between consecutive events. For sample t in [t_k, t_{k+1}), phase = 2π · (t - t_k) / (t_{k+1} - t_k). Suited to irregular event-driven streams. Both return double[] of phase values in [0, 2π) radians. Empty output on degenerate inputs (no exception). eventTimes assumed sorted ascending; samples outside the event range get 0 phase (callers filter to interior if they care). Hilbert-transform analytic-signal approach (Amara's Option B) deferred — needs FFT support which Zeta doesn't currently ship. Future graduation when signal-processing substrate lands. Tests (12, all passing): epochPhase: - t=0 → phase 0 - t=period/2 → phase π - wraps cleanly at period boundary - handles negative sample times correctly - returns empty on invalid period (≤0) or empty samples interEventPhase: - empty on <2 events or empty samples - phase 0 at start of first interval - phase π at midpoint - adapts to varying interval lengths (O(log n) binary search for bracketing interval) - returns 0 before first and after last event (edge cases) Composition with phaseLockingValue: - Two nodes with identical epochPhase period → PLV = 1 (synchronized) - Two nodes with same period but constant offset → PLV = 1 (perfect phase locking at non-zero offset is still locking) This composes the full firefly-synchronization detection pipeline end-to-end for event-driven validator streams: validator event times → PhaseExtraction → phaseLockingValue → temporal-coordination-detection signal 5 of 8 Amara 17th-ferry corrections now shipped: #1 λ₁(K₃)=2 ✓ already correct (PR #321) #2 modularity relational ✓ already correct (PR #324) #3 cohesion/exclusivity/conductance ✓ shipped (PR #331) #4 windowed stake covariance ✓ shipped (PR #331) #5 event-stream → phase pipeline ✓ THIS SHIP Remaining: #4 robust-z-score composite variant (future); #6 ADR phrasing (already correct); #7 KSK naming (BACKLOG #318 awaiting Max coord); #8 SOTA humility (doc-phrasing discipline). Build: 0 Warning / 0 Error. Provenance: - Concept: Aaron firefly-synchronization design - Formalization: Amara 17th-ferry correction #5 with 3-option menu (epoch / Hilbert / circular) - Implementation: Otto (17th graduation; options A + C shipped, Hilbert deferred) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
Adds a PhaseExtraction layer in Zeta.Core to complete the TemporalCoordinationDetection.phaseLockingValue pipeline by converting event-time streams into phase series (radians), with tests demonstrating correctness and PLV composition.
Changes:
- Added
PhaseExtractionmodule withepochPhaseandinterEventPhasepure functions. - Added F# test coverage for both functions plus PLV integration scenarios.
- Registered the new source + test files in their respective
.fsprojcompile lists.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/Tests.FSharp/Tests.FSharp.fsproj | Includes new PhaseExtraction test file in compile order. |
| tests/Tests.FSharp/Algebra/PhaseExtraction.Tests.fs | Adds unit tests for epoch/inter-event phase extraction and PLV composition. |
| src/Core/PhaseExtraction.fs | Introduces phase extraction functions and module-level documentation. |
| src/Core/Core.fsproj | Adds PhaseExtraction module to Core compilation list. |
| /// events. For a node whose events occur at irregular times | ||
| /// `t_1 < t_2 < …`, the phase at sample time `t` is | ||
| /// `φ(t) = 2π · (t − t_k) / (t_{k+1} − t_k)` where | ||
| /// `t_k ≤ t < t_{k+1}`. Suited to event-driven streams | ||
| /// without fixed periods. |
There was a problem hiding this comment.
P1: interEventPhase’s contract is internally inconsistent: the module docs describe irregular events as t_1 < t_2 < … (strictly increasing), but the function docs only require “sorted ascending”, and the implementation explicitly handles interval <= 0.0 by returning phase 0.0. Please align the API contract and behavior (e.g., require strictly increasing eventTimes and validate/return empty on violation, or document duplicate/non-increasing handling and recommend pre-dedup/filtering).
…18th graduation (Amara #4 robust) Two ships consolidated per the 'parallel PRs hit positional conflicts on tail-append' lesson: 1. RobustStats.robustZScore (baseline: double seq) -> (measurement: double) -> double option Returns (measurement - median) / (1.4826 · MAD). The 1.4826 constant scales MAD to be consistent with Gaussian stddev. MadFloor prevents blow-up when every baseline value equal. 2. Graph.coordinationRiskScoreRobust alpha beta eigenTol eigenIter lpIter (baselineLambdas: double seq) (baselineQs: double seq) (attacked: Graph<'N>) -> double option Upgrades coordinationRiskScore (PR #328) from raw linear differences to robust-standardized z-scores per Amara 17th-ferry correction #4. Caller provides baseline metric distributions; Z-scores calibrate thresholds from data. Why robust z-scores: adversarial data isn't normally distributed. An attacker can poison a ~normal distribution by adding a few outliers that inflate stddev, making subsequent real attacks look 'within one sigma'. Median+MAD survives ~50% adversarial outliers. Standard move in robust statistics literature; Amara's correction puts it on the Zeta composite. Tests (5 new; total 39 since main hasn't merged #331/#332 yet): - robustZScore None on empty baseline - robustZScore of measurement = median is 0 - robustZScore scales MAD by 1.4826 for Gaussian consistency (measurement 4 on baseline [1..5] ≈ 0.674) - coordinationRiskScoreRobust fires strongly on K4-injected graph given 5 baseline samples - coordinationRiskScoreRobust returns None on empty baselines BACKLOG rows added this tick per Aaron Otto-139 directives: 1. Signal-processing primitives (FFT + Hilbert) — unblocks Amara correction #5 Option B; Aaron standing-approval 2. F# DSL for entry points + graph-query-language standards compliance (Cypher / GQL / Gremlin / SPARQL / Datalog) 3. LINQ-compatible entry points for C# consumers — pair with F# DSL; two frontends, one algebraic backend 6 of 8 Amara 17th-ferry corrections now shipped or confirmed: Remaining: #6 ADR phrasing (already fine); #7 KSK naming (BACKLOG #318 Max coord pending); #8 SOTA humility (doc-phrasing discipline ongoing). Build: 0 Warning / 0 Error. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…mara #4 robust) + 3 BACKLOG rows (#333) * core: RobustStats.robustZScore + Graph.coordinationRiskScoreRobust — 18th graduation (Amara #4 robust) Two ships consolidated per the 'parallel PRs hit positional conflicts on tail-append' lesson: 1. RobustStats.robustZScore (baseline: double seq) -> (measurement: double) -> double option Returns (measurement - median) / (1.4826 · MAD). The 1.4826 constant scales MAD to be consistent with Gaussian stddev. MadFloor prevents blow-up when every baseline value equal. 2. Graph.coordinationRiskScoreRobust alpha beta eigenTol eigenIter lpIter (baselineLambdas: double seq) (baselineQs: double seq) (attacked: Graph<'N>) -> double option Upgrades coordinationRiskScore (PR #328) from raw linear differences to robust-standardized z-scores per Amara 17th-ferry correction #4. Caller provides baseline metric distributions; Z-scores calibrate thresholds from data. Why robust z-scores: adversarial data isn't normally distributed. An attacker can poison a ~normal distribution by adding a few outliers that inflate stddev, making subsequent real attacks look 'within one sigma'. Median+MAD survives ~50% adversarial outliers. Standard move in robust statistics literature; Amara's correction puts it on the Zeta composite. Tests (5 new; total 39 since main hasn't merged #331/#332 yet): - robustZScore None on empty baseline - robustZScore of measurement = median is 0 - robustZScore scales MAD by 1.4826 for Gaussian consistency (measurement 4 on baseline [1..5] ≈ 0.674) - coordinationRiskScoreRobust fires strongly on K4-injected graph given 5 baseline samples - coordinationRiskScoreRobust returns None on empty baselines BACKLOG rows added this tick per Aaron Otto-139 directives: 1. Signal-processing primitives (FFT + Hilbert) — unblocks Amara correction #5 Option B; Aaron standing-approval 2. F# DSL for entry points + graph-query-language standards compliance (Cypher / GQL / Gremlin / SPARQL / Datalog) 3. LINQ-compatible entry points for C# consumers — pair with F# DSL; two frontends, one algebraic backend 6 of 8 Amara 17th-ferry corrections now shipped or confirmed: Remaining: #6 ADR phrasing (already fine); #7 KSK naming (BACKLOG #318 Max coord pending); #8 SOTA humility (doc-phrasing discipline ongoing). Build: 0 Warning / 0 Error. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(#333): 4 review-thread P1/P2s on robustZScore + coordinationRiskScoreRobust Active PR-resolve-loop on #333. 1. Doc/impl contradiction on MAD=0 (thread 59VhYb, P1): RobustStats.robustZScore doc said "returns None when MAD(baseline)=0" but impl uses MadFloor and returns Some finite value. Rewrote doc to match impl: explicit "MadFloor substituted when MAD collapses to zero" — floor reflects "scale is below epsilon" not "undefined." Implementation is the contract. 2. Multi-enumeration of baseline seq (thread 59VhYq, P1): robustZScore previously passed `baseline` to both `median` + `mad` which each call `Seq.toArray`. Expensive AND inconsistent for lazy/non-repeatable sequences (different values between enumerations = undefined behavior). Fixed: `Seq.toArray` once at entry, pass the materialized array to both. O(n) instead of O(2n); stable across lazy sources. 3. Name attribution in Graph.fs doc comment (thread 59VhY5, P1): "Amara 17th-ferry... Otto 18th graduation" → "external AI collaborator's 17th courier ferry... Eighteenth graduation under the Otto-105 cadence." Role-reference convention per AGENT-BEST-PRACTICES code/doc rule. 4. Array-vs-seq terminology (thread 59VhZG, P2): Graph.fs doc said callers "provide arrays" but the API is `double seq`. Rewrote: sequences + noted the materialize-once optimization in robustZScore so callers can pass any seq form without re-enumeration cost. Thread 59VhX9 (P3-label-in-P2-section mismatch) — already resolved on main via PR #341 which landed the signal- processing row correctly labeled "P2 research-grade." No fix needed on this branch. Build: 0 Warning(s) / 0 Error(s). 53 RobustStats + Graph tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…Corrections
Two-part ferry from Aaron Otto-157/158 tick boundary:
Part 1 — Deep research on Cartel-Lab calibration + CI hardening
(~4000 words; 8 sections A-H + action items + Mermaid diagrams):
- Null-models table (6 types: Erdős-Rényi, configuration,
stake-shuffle, temporal-shuffle, clustered-honest, noise)
- CoordinationRiskScore formula with 6 robust-z terms +
default weights α=β=0.20, γ=ε=0.15, δ=0.20, η=0.10
- 8-row adversarial scenario table (obvious clique → stealth
→ synchronized voting → honest cluster → low-weight →
camouflage → rotating → cross-coalition)
- 4-PR roadmap: seed-lock/CI governance → calibration harness
→ adversarial scenarios → docs/promotion criteria
- KSK/Aurora integration: advisory-only flow
(Detection → Oracle → KSK → Action)
- "What not to claim" caveats (6 items: no proof of intent,
not all collusion detectable, not production-ready, etc.)
Part 2 — Amara's own GPT-5.5 Thinking correction pass on Part 1
(~1500 words; 10 required corrections; repo-safe status
statement; corrected promotion ladder + PR roadmap titles):
- #1: replace "CI confirms" with "PR #323 clears toy
falsifiability bar"
- #2: Wilson intervals replace handwave ±5% CI (90/100 →
LB only 82.6%; 20/100 FPR → UB 28.9%)
- #3: rename "Cartel Score" → "CoordinationRiskScore" locked
- #4: conductance sign flip — use Z(-conductance) or
Z(exclusivity), not Z(+conductance)
- #5: modularity relational — use Q(attacked)-Q(baseline)>θ
not absolute Q thresholds
- #6: PLV phase-offset — PLV=1 can mean anti-phase; need
magnitude AND mean phase offset
- #7: MAD=0 fallback — epsilon floor or percentile-rank
- #8: replace Medium-article source with scikit-learn
precision-recall docs
- #9: explicit artifact output layout
(calibration-summary.json, seed-results.csv, etc.)
- #10: sharder — measure variance before widening threshold
Corrected promotion ladder (0-6 stages):
0 Theory / 1 Toy detector / 2 Calibration harness /
3 Scenario suite / 4 Advisory engine / 5 Governance integration /
6 Enforcement candidate
PR #323 is Stage 1, NOT Stage 4.
Otto's operationalization notes:
- 4/10 corrections already aligned with shipped substrate:
#4 exclusivity (PR #331), #5 modularity relational
(PR #324), #7 MAD floor (PR #333), #10 sharder Otto-132
(BACKLOG #327).
- 6/10 queued as future graduations: Wilson CIs in tests;
MAD=0 percentile-rank fallback; conductance-sign doc;
PLV phase-offset extension; CI test classification;
artifact-output layout.
Invariant restated (Amara 16th-ferry carry-over):
"Every abstraction must map to a repo surface, a test,
a metric, or a governance rule."
Cross-ref verified: PRs #321 #323 #324 #326 #327 #331 #332
#333, docs/definitions/KSK.md (Otto-157 / #336), 17th ferry
(#330), 16th ferry, 15th ferry, Otto-140..145 memory.
GOVERNANCE §33 four-field header (Scope / Attribution /
Operational status / Non-fusion disclaimer).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ns (10 tracked; 4 already shipped, 6 queued) (#337) * ferry: Amara 18th absorb — Calibration + CI Hardening + 5.5-Thinking Corrections Two-part ferry from Aaron Otto-157/158 tick boundary: Part 1 — Deep research on Cartel-Lab calibration + CI hardening (~4000 words; 8 sections A-H + action items + Mermaid diagrams): - Null-models table (6 types: Erdős-Rényi, configuration, stake-shuffle, temporal-shuffle, clustered-honest, noise) - CoordinationRiskScore formula with 6 robust-z terms + default weights α=β=0.20, γ=ε=0.15, δ=0.20, η=0.10 - 8-row adversarial scenario table (obvious clique → stealth → synchronized voting → honest cluster → low-weight → camouflage → rotating → cross-coalition) - 4-PR roadmap: seed-lock/CI governance → calibration harness → adversarial scenarios → docs/promotion criteria - KSK/Aurora integration: advisory-only flow (Detection → Oracle → KSK → Action) - "What not to claim" caveats (6 items: no proof of intent, not all collusion detectable, not production-ready, etc.) Part 2 — Amara's own GPT-5.5 Thinking correction pass on Part 1 (~1500 words; 10 required corrections; repo-safe status statement; corrected promotion ladder + PR roadmap titles): - #1: replace "CI confirms" with "PR #323 clears toy falsifiability bar" - #2: Wilson intervals replace handwave ±5% CI (90/100 → LB only 82.6%; 20/100 FPR → UB 28.9%) - #3: rename "Cartel Score" → "CoordinationRiskScore" locked - #4: conductance sign flip — use Z(-conductance) or Z(exclusivity), not Z(+conductance) - #5: modularity relational — use Q(attacked)-Q(baseline)>θ not absolute Q thresholds - #6: PLV phase-offset — PLV=1 can mean anti-phase; need magnitude AND mean phase offset - #7: MAD=0 fallback — epsilon floor or percentile-rank - #8: replace Medium-article source with scikit-learn precision-recall docs - #9: explicit artifact output layout (calibration-summary.json, seed-results.csv, etc.) - #10: sharder — measure variance before widening threshold Corrected promotion ladder (0-6 stages): 0 Theory / 1 Toy detector / 2 Calibration harness / 3 Scenario suite / 4 Advisory engine / 5 Governance integration / 6 Enforcement candidate PR #323 is Stage 1, NOT Stage 4. Otto's operationalization notes: - 4/10 corrections already aligned with shipped substrate: #4 exclusivity (PR #331), #5 modularity relational (PR #324), #7 MAD floor (PR #333), #10 sharder Otto-132 (BACKLOG #327). - 6/10 queued as future graduations: Wilson CIs in tests; MAD=0 percentile-rank fallback; conductance-sign doc; PLV phase-offset extension; CI test classification; artifact-output layout. Invariant restated (Amara 16th-ferry carry-over): "Every abstraction must map to a repo surface, a test, a metric, or a governance rule." Cross-ref verified: PRs #321 #323 #324 #326 #327 #331 #332 #333, docs/definitions/KSK.md (Otto-157 / #336), 17th ferry (#330), 16th ferry, 15th ferry, Otto-140..145 memory. GOVERNANCE §33 four-field header (Scope / Attribution / Operational status / Non-fusion disclaimer). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * ferry: fix markdownlint MD018 — line-start #221 parsed as H1 heading * ferry: drain PR #337 review threads — 4 FIX, 2 NARROW+BACKLOG, 8 BACKLOG+RESOLVE Factory-authored sections of the 18th-ferry absorb (header, Otto's notes, Cross-references) edited under name-attribution + code-comments-not-history disciplines; Amara's verbatim Part 1 + Part 2 body left intact per verbatim-preserve. In-doc edits: - Soften "verified against actual" wording on the CLAUDE.md cross-reference bullet to anchor-list rechecked-at-drain-time framing. - Use full `tests/Tests.FSharp/Simulation/` path in the Stage-discipline section (was bare `tests/Simulation/`). - Replace dead "GOVERNANCE §33" cite with factory-convention + CLAUDE.md ground-rule pointer (numbered §33 not yet landed; rule is captured by convention across docs/aurora/** absorbs). - Drop broken `feedback_ksk_naming_*.md` filename and soften 15th/16th ferry cross-refs to "not present as a dedicated absorb in this snapshot." Drain-log: docs/pr-preservation/337-drain-log.md per Otto-250. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Completes the TemporalCoordinationDetection.phaseLockingValue pipeline: event streams → phase series → PLV.
2 pure functions (epochPhase + interEventPhase); 12 tests passing. Composes end-to-end with PLV for synchronized and constant-offset sources.
5 of 8 Amara 17th-ferry corrections now shipped.